package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.pojos.*;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.*;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.Tesseract;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: heima-leadnews
 * @description: 自媒体文章审核实现
 * @author: ryp
 * @create: 2023-04-29 17:20
 **/
@Slf4j
@Service
@Transactional
public class WmNewsAutoScanServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsAutoScanService {
    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private IArticleClient articleClient;

    @Autowired
    private Tess4jClient tess4jClient;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private WmChannelMapper wmChannelMapper;
    @Autowired
    private WmUserMapper wmUserMapper;

    /**
     * 功能描述:
     *
     * @param id
     * @return : void
     */
    /**
     * 功能描述: 异步进行文章审核业务-文章提交审核后进行自动文章审核
     * @param id
     * @return : void
     */
    @Async
    @Override
    public void autoScanWmNews(Integer id) throws Exception {
        //检查参数
        if (id == null){
            return;
        }
        //根据文章id获取文章内容对象
        WmNews wmNews = wmNewsMapper.selectById(id);
        //校验,是否存在文章内容
        if (wmNews == null){
            return;
        }
        //3.内容不为空，进行文字内容审核：标题、标签、文章内容，审核失败直接修改文章状态、给出失败原因，返回。
        //3.1 提取文章中文本内容信息
        //标题
        String title = wmNews.getTitle();
        //标签
        String tag = wmNews.getLabels();
        //文章内容(图片+文字)
        String content = wmNews.getContent();
        //获取文章内容的json字符串集合
        List<String> contents = getContentTextList(content);
        //将(标题)与(标签)中的字符串合在一起,为了省钱
        contents.add(title);
        contents.add(tag);
        //以","隔开,转成json字符串
        String contentResult = StringUtils.join(contents, ",");
        /*111111111111111111111111111111111111111111111111111111111111111111111111111111*/

        //自定义敏感词
        boolean isSensitive = handleSensitiveScan(contentResult, wmNews);
        if(isSensitive == true) {
            Map map = greenTextScan.greeTextScan(contentResult);
            String suggestion = (String) map.get("suggestion");
            if ("block".equals(suggestion)) {
                wmNews.setStatus((short) 2);
                String label = (String) map.get("label");
                wmNews.setReason("内容存在违规" + label);
                wmNewsMapper.updateById(wmNews);
                return;
            }
            if ("review".equals(suggestion)) {
                wmNews.setStatus((short) 3);
                String label = (String) map.get("label");
                wmNews.setReason("内容存在可疑" + label);
                wmNewsMapper.updateById(wmNews);
                return;
            }
        }else {
            return;
        }
        /*111111111111111111111111111111111111111111111111111111111111111111111111111111111111*/


        //4.图片内容不为空（封面图片和内容图片进行整体的去重处理-省钱），进行图片审核：封面图片、内容图片，审核失败直接修改文章状态、给出失败原因返回。
        //获取内容中图片
        Set<String> contentImageList = getContentImageList(content);
        //获取封面中的图片
        String images = wmNews.getImages();
        String[] coverImageList = images.split(",");
        //(内容图片)和(封面图片)合并
        Collections.addAll(contentImageList, coverImageList);
        //根据URL地址，下载图片，获取图片的字节数组
        List<byte[]> imgList = new ArrayList<>();
        for (String imgUrl : contentImageList) {
            //获取minion中返回的图片字节
            byte[] bytes = fileStorageService.downLoadFile(imgUrl);
            imgList.add(bytes);
        }

        //上传图片,进行审核
        Map imgResultMap = greenImageScan.imageScan(imgList);
        String imgSuggestion = (String)imgResultMap.get("suggestion");
        if("block".equals(imgSuggestion)){
            wmNews.setStatus((short)2);
            String label = (String)imgResultMap.get("label");
            wmNews.setReason("文章中图片存在违规内容："+label);
            wmNewsMapper.updateById(wmNews);
            return;
        }
        if("review".equals(imgSuggestion)){
            wmNews.setStatus((short)3);
            String label = (String)imgResultMap.get("label");
            wmNews.setReason("文章中图片存在可疑内容："+label);
            wmNewsMapper.updateById(wmNews);
            return;
        }



        //5.图片中文字审核：提取图片中文字，进行审核，，审核失败直接修改文章状态、给出失败原因，返回。--TODO
        ArrayList<String> imgStrList = new ArrayList<>();
        for (byte[] bytes : imgList) {
            ByteArrayInputStream in = new ByteArrayInputStream(bytes);
            BufferedImage imageFile = ImageIO.read(in);
            String result = tess4jClient.doOCR(imageFile);
            imgStrList.add(result);
        }
        String imgCharacter = StringUtils.join(imgStrList, ",");

        //自定义文字审核
        boolean isSensitive2 = handleSensitiveScan(contentResult, wmNews);
        if(isSensitive2 == true) {
            Map imgCharScanResult = greenTextScan.greeTextScan(imgCharacter);
            String imgCharScanResultSuggestion = (String) imgCharScanResult.get("suggestion");
            if ("block".equals(imgCharScanResultSuggestion)) {
                wmNews.setStatus((short) 2);
                String label = (String) imgCharScanResult.get("label");
                wmNews.setReason("文章中图片存在违规文字：" + label);
                wmNewsMapper.updateById(wmNews);
                return;
            }
            if ("review".equals(imgCharScanResultSuggestion)) {
                wmNews.setStatus((short) 3);
                String label = (String) imgCharScanResult.get("label");
                wmNews.setReason("文章中图片存在可疑文字：" + label);
                wmNewsMapper.updateById(wmNews);
                return;
            }
        }else {
            return;
        }

        /*111111111111111111111111111111111111111111111111111111111111111111111111111*/

        //获取当前时间
        Date currentDate = new Date();
        short status = 8;
        //获取当前时间,与,数据库中,数据的,时间的,毫秒值,进行对比
        if (wmNews.getPublishTime().getTime() <= currentDate.getTime()){
            status = 9;
        }

        wmNews.setStatus(status);
        //ResponseResult result = articleClient.saveArticle();---



        //调用App文章保存接口
        ResponseResult result = saveAppArticle(wmNews);
        wmNews.setArticleId((Long) result.getData());



        wmNewsMapper.updateById(wmNews);
        return;


    }




    /**
     * 自管理的敏感词审核
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleSensitiveScan(String content, WmNews wmNews) {

        boolean flag = true;

        //获取所有的敏感词
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
        List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

        //初始化敏感词库
        SensitiveWordUtil.initMap(sensitiveList);

        //查看文章中是否包含敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if(map.size() >0){
            updateWmNews(wmNews,(short) 2,"当前文章中存在违规内容"+map);
            flag = false;
        }

        return flag;
    }


    /**
     * 修改文章内容
     * @param wmNews
     * @param status
     * @param reason
     */
    private void updateWmNews(WmNews wmNews, short status, String reason) {
        //修改状态
        wmNews.setStatus(status);
        //修改原因
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }


    /**
     * 功能描述: 封装WmNews对象
     *
     * @param dto
     * @param wmNews
     * @return : com.heima.model.wemedia.pojos.WmNews
     */

    public WmNews completion(WmNewsDto dto, WmNews wmNews,boolean boo) {
        //将传入的对象拷贝到实体类中
        BeanUtils.copyProperties(dto, wmNews);
        //补全实体类中缺少的
        wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
        wmNews.setCreatedTime(new Date());
        //判断是否为草稿
        if (boo == true){
            wmNews.setStatus((short) 0);
        }else {
            wmNews.setStatus((short) 1);
        }

        wmNews.setEnable((short) 1);
        //获取图片集合
        List<String> imageList = dto.getImages();
        if (dto.getType() == -1) {//类型为自动(没传封面图)
            short type = 0;
            //从内容中提取图片信息
            HashSet<String> imgs = new HashSet<>();
            String content = dto.getContent();
            if (StringUtils.isNotBlank(content)) {
                List<WmNewsContent> contentList = JSONObject.parseArray(content, WmNewsContent.class);
                for (WmNewsContent wmNewsContent : contentList) {
                    if ("image".equals(wmNewsContent.getType())) {
                        imgs.add(wmNewsContent.getValue());
                        continue;
                    }
                }
            }
            int size = imgs.size();
            if (size < 1) {
                type = 0;
            } else if (size >= 3) {
                type = 3;
                imageList = imgs.stream().limit(3).collect(Collectors.toList());
            } else {
                type = 1;
                imageList = imgs.stream().limit(1).collect(Collectors.toList());
            }
            wmNews.setType(type);
        }
        wmNews.setImages(StringUtils.join(imageList, ","));//现成方法
        return wmNews;
    }



    /**
     * 功能描述:删除文章和素材关系
     *
     * @param id
     * @return : void
     */
    public void removeRelationship(Integer id) {
        LambdaQueryWrapper<WmNewsMaterial> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WmNewsMaterial::getNewsId, id);
        wmNewsMaterialMapper.delete(queryWrapper);
    }


    /**
     * 功能描述: 获取封面图片列表
     *
     * @param dto
     * @return : java.util.List<java.lang.String>
     */
    public List<String> coverImages(WmNewsDto dto) {
        //获取图片集合
        List<String> imageList = dto.getImages();
        if (dto.getType() == -1) {//类型为自动(没传封面图)
            short type = 0;
            //从内容中提取图片信息
            HashSet<String> imgs = new HashSet<>();
            String content = dto.getContent();
            if (StringUtils.isNotBlank(content)) {
                List<WmNewsContent> contentList = JSONObject.parseArray(content, WmNewsContent.class);
                for (WmNewsContent wmNewsContent : contentList) {
                    if ("image".equals(wmNewsContent.getType())) {
                        imgs.add(wmNewsContent.getValue());
                        continue;
                    }
                }
            }
            int size = imgs.size();
            if (size < 1) {
                type = 0;
            } else if (size >= 3) {
                type = 3;
                imageList = imgs.stream().limit(3).collect(Collectors.toList());
            } else {
                type = 1;
                imageList = imgs.stream().limit(1).collect(Collectors.toList());
            }
        }

        return imageList;
    }




    /**
     * 功能描述: 根据素材的URL地址,获取素材的id列表
     * @param dto
     * @return : java.util.List<java.lang.Integer>
     */
    public List<Integer> getMetarialIds(WmNewsDto dto){
        List<String> coverImages = coverImages(dto);

        //封面无图时,下面queryWrapper.in,中的条件为空,规定不能为空
        if (coverImages == null || coverImages.size() == 0){
            return new ArrayList<>();
        }
        LambdaQueryWrapper<WmMaterial> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(WmMaterial::getUrl,coverImages);
        queryWrapper.select(WmMaterial::getId);
        List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(queryWrapper);
        List<Integer> wmMaterialIds = wmMaterials.stream().map(wmMaterial -> wmMaterial.getId()).collect(Collectors.toList());
        return wmMaterialIds;
    }


    /**
     * 功能描述: 获取文章的所有文本内容
     * @param content 自媒体文章内容，JsonArray类型字符串 "[{},{},{}]"
     * @return : java.util.List<java.lang.String>
     */
    public List<String> getContentTextList(String content){
        List<String> contents = new ArrayList<>();
        List<WmNewsContent> contentList = JSON.parseArray(content, WmNewsContent.class);
        for (WmNewsContent wmNewsContent : contentList) {
            if("text".equals(wmNewsContent.getType())){
                contents.add(wmNewsContent.getValue());
            }
        }
        return contents;
    }


    /**
     * 功能描述: 获取文章内容中图片列表
     * @param content 文章内容的JsonArray字符串
     * @return : java.util.Set<java.lang.String>
     */
    public Set<String> getContentImageList(String content){
        //从内容中提取图片信息
        Set<String> imgs = new HashSet<>();
        if (StringUtils.isNotBlank(content)) {
            List<WmNewsContent> contentList = JSONObject.parseArray(content, WmNewsContent.class);
            for (WmNewsContent wmNewsContent : contentList) {
                if ("image".equals(wmNewsContent.getType())) {
                    imgs.add(wmNewsContent.getValue());
                    continue;
                }
            }
        }
        return imgs;
    }



    /**
     * 保存app端相关的文章数据
     * @param wmNews
     */
    private ResponseResult saveAppArticle(WmNews wmNews) throws Exception {

        ArticleDto dto = new ArticleDto();
        //属性的拷贝
        BeanUtils.copyProperties(wmNews,dto);
        //文章的布局
        dto.setLayout(wmNews.getType());
        //频道
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if(wmChannel != null){
            dto.setChannelName(wmChannel.getName());
        }

        //作者
        dto.setAuthorId(wmNews.getUserId().longValue());
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if(wmUser != null){
            dto.setAuthorName(wmUser.getName());
        }

        //设置文章id
        if(wmNews.getArticleId() != null){
            dto.setId(wmNews.getArticleId());
        }
        dto.setCreatedTime(new Date());
        //远程feign调用App文章添加
        ResponseResult responseResult = articleClient.saveArticle(dto);
        return responseResult;

    }

}